<?php
/**
 * Subscription class.
 *
 * 
 * 
 * Responsible for the creation, reading, updating, deletion, and management of the Subscriptions.
 * Interfaces with tables: Subscription, Allowance, User, Publication
 * 
 * To retrieve subscriptions from the database use find_by_publication
 * To retrieve a single subscription use find_by_user
 * 
 * 
 * PHP version 5
 *
 * LICENSE: This source file is subject to version 3.01 of the PHP license
 * that is available through the world-wide-web at the following URI:
 * http://www.php.net/license/3_01.txt.  If you did not receive a copy of
 * the PHP License and are unable to obtain it through the web, please
 * send a note to license@php.net so we can mail you a copy immediately.
 *
 * @package    Subbear Subscription Management
 * @author     Shawn Wernig ( shawn@eggplantstudios.ca )
 * @copyright  2013 
 * @license    http://www.eggplantstudios.ca
 * @version    2.0
 */


class Subscription  {

    public $subscription_id;
    public $user_id;
    public $user;
    public $publication_id;
    public $publication;
    public $allowances = array(); // array/
    
    public $subscription_datestamp;
    public $user_datestamp;
           
    public $start_date;
    public $start_week;
    public $trashed;
    
    public $subscription_length;
    public $subscription; // array
    
    public $status; // (active/paused/inactive)
    public $end_date;
    
    
    private static $table_name = "_subscription";
    
    /* --------------------------------------- init --------------------------------------- */

    
    /**
     * Initializes an instance of this class by an array, takes some optional parameters to expand the data set.
     *
     * @return object
     * @author epstudios
     */  
    public function __construct($record) {
        
        $this->_instantiate($record);
        if( isset($_POST['action']) && $_POST['action'] ==  'update_subscription') return;
        // Add publication
        $this->publication = Publication::instantiate($record);
        $this->user = User::instantiate( $record );
        $this->_build_subscription_array( $record );
        
    }
    

    /**
     * BUILD SUBSCRIPTION ARRAY builds the subscription array of 1s and 2s for the 
     * duration of this subscription according do this subscriptions allowance(s)
     * 
     * @return object
     * @author epstudios
     */  
    private function _build_subscription_array( $record ) {
        if ( $this->is_new() ) return;
        

        $allowance_ids = explode(',', $record['allowance_ids'] );
        $total_durations = explode(',', $record['total_durations'] );
        $datestamps = explode(',', $record['datestamps'] );
        $queues = explode(',', $record['queues'] );
        $types = explode(',', $record['types'] );
        $total_allowances = count( $allowance_ids );
        
        $this->subscription_length = array_sum($total_durations);
        
        for( $i = 0; $i < $total_allowances; $i ++ ) {
            $this->allowances[] = Allowance::instantiate( array(
                'allowance_id'      => $allowance_ids[$i],
                'total_duration'   => $total_durations[$i],
                'datestamp'        => $datestamps[$i],
                'queue'            => $queues[$i],
                'type'             => $types[$i]
            ));
        }
        
        
        $available_weeks = $this->get_current_week();
        $counter = 0;
        $this->allowances = array_reverse( $this->allowances );
        foreach ($this->allowances as $allowance ) {
            
            if( $available_weeks > 0 ) {
                
                if($available_weeks > $allowance->total_duration) {
                    $allowance->current_duration = $allowance->total_duration;
                    $available_weeks -=  $allowance->total_duration;
                } else {
                    $allowance->current_duration = $available_weeks;
                    $available_weeks = 0;
                }
                
            } else {
                $allowance->current_duration = 0;
            }
            
            $counter ++;
            
            for ($i = 0; $i < $allowance->total_duration; $i ++ ) {
                $this->subscription[] =  $allowance->get_type_code();
            }
        }
        
        

    }
    
    /* --------------------------------------- GETS --------------------------------------- */

    
    /**
     * BUILD SUBSCRIPTION ARRAY builds the subscription array of 1s and 2s for the 
     * duration of this subscription according do this subscriptions allowance(s)
     * 
     * @status Deprecated??
     * @return object
     * @author epstudios
     */ 
    function _get_status_for_week($cur_week_num) {
        // returns the status for any given week num.
        
        if ($cur_week_num >  $this->start_week) {
            return $this->_get_status( $cur_week_num - $this->start_week );
        } elseif ($cur_week_num == $this->start_week) {
            return 'current';
        }
        return 'inactive'; // This subscription was inactive.
    }

    /**
     * Gets a status. Since a status can be both expiring and paused, the Raw parameter will override.
     * 
     * @return object
     * @author epstudios
     */ 
    public function get_status( $raw = false ) {
        if ( isset($raw) ) return $this->status;
        // Returns the status string for the local week_num, or array position of this->subscription
        if ( $this->status == 'paused' ) {
            if ( $this->subscription_length - ($sub->get_current_week() + 1 ) <= $session->publication->setting_expiring_tolerance ) {
                return 'expiring';
            }
        }
        return $this->status;
    }
    
    public function get_percent() {
        if( !isset($this->subscription_length) ) return false;
        $percent = round( $this->get_current_week() / $this->subscription_length, 2) * 100;
        return ( $percent > 100 ) ? 100 : $percent;
    }
    /**
     * Checks if this sub has recently expired.
     * 
     * @return bool
     * @author epstudios
     */ 
     
    public function recently_expired(){
        global $session;
        $offset = $this->subscription_length - $this->get_current_week();
        $offset = abs($offset);
        return ( $offset <= $session->publication->setting_expiring_tolerance ) ? true : false;
    }
    

    /**
     * Gets the full table name for this subscritpion
     *
     * @return string
     * @author epstudios
     */
    public static function get_tablename() {
        global $TABLE_PREFIX;
        return $TABLE_PREFIX . self::$table_name; 
    }
    
    /**
     * Gets an attribute
     *
     * @return void
     * @param $object = the object to display; Typically a class, or array.
     * @author epstudios
     */       
    public function attr($attr) {
        echo htmlspecialchars($this->$attr);
    }
    public function get_attr($attr) {
        return  $this->$attr;
    }
    
        
     
    /**
     * Discover if a given user has a currently active sub.
     *
     * @return bool
     * @param $user_id, $publication_id
     * @author epstudios
     */ 
    public static function has_subscription($user_id, $publication_id = null ){
        global $db, $session;
        if(!isset($publication_id)) $publication_id = $session->publication->publication_id;
        if(!isset($user_id)) return false;
        
        $subs = self::find_by_user_id( $user_id );
        if( !$subs ) return false;
        foreach( $subs as $sub ) {
            if ( isset( $sub->subscription_length ) && $sub->subscription_length > 0 && $sub->status != 'inactive' ) {
                return true;  
                
            } 
        } 
        return false;
    }
    
    public function is_subscribed() {
        return ( isset( $sub->subscription_length ) && $sub->subscription_length > 0  )  ? true : false;
    }
    
    function get_end_date(){
        $this->end_date = date( "M-d-Y", get_date_from_weeknum( ($this->start_week) + count($this->subscription) - 1 ));
        return htmlspecialchars($this->end_date);
    }
    function get_current_week() {
        return get_weeknum() - htmlspecialchars( $this->start_week ); // TODO RETURN THIS TO NORMAL
    }
    function get_start_week() {
        return $this->start_week;
    }
    function current_week(){
        $current_week = get_weeknum() - htmlspecialchars($this->start_week) ;
        echo htmlspecialchars($current_week);
    }
    function subscription_length() {
        return htmlspecialchars($this->subscription_length);
    }

    function get_user_object() {
        return ( isset($this->user) ) ? $this->user : User::find_by_id($this->user_id);
    }
    
    public static function get_total_subscriptions($filter = null){
        global $db;
        if (!$filter) {
                    $result = $db->query( "SELECT subscription_id FROM " . self::get_tablename() . " WHERE trashed = 0 AND status!='inactive'" );
        } else {
                    $result = $db->query( "SELECT subscription_id FROM " . self::get_tablename() . " WHERE trashed = 0 AND status='" . $filter ."'" );
        }
        return $result->num_rows;
    }
    
    
    public static function get_start_date_by_id($subscription_id){
        global $db;    
        $result_set = $db->query( "SELECT start_week FROM " . self::get_tablename() . " WHERE trashed = 0 AND status!='inactive' AND subscription_id={$subscription_id} LIMIT 1" );
        
        $result = $db->fetch_array($result_set);
        $result = date("F j Y", get_date_from_weeknum( $result['start_week'] - 1 ));
        return $result;
    }
    public static function get_start_week_by_id($subscription_id){
        global $db;    
        $result_set = $db->query( "SELECT start_week FROM " . self::get_tablename() . " WHERE trashed = 0 AND status!='inactive' AND subscription_id={$subscription_id} LIMIT 1" );
        $result = $db->fetch_array($result_set);
        return $result['start_week'];
    }
    
    /* --------------------------------------- BOOLS --------------------------------------- */

    /**
     * If this instance has been pulled from the database, or updated, there will be an ID. 
     * If created from a POST for example, there will be no id.
     *
     * @return void
     * @param bool 
     * @author epstudios
     */ 
    public function is_new(){
        return (!isset($this->subscription_id) || $this->subscription_id == 0) ? true : false ;
    }
        
        
    function is_active() { return ($this->status != 'inactive' ) ? true : false; }
    
    function is_paused() {  return ($this->status == 'paused' ) ? true : false;  }
    
    function is_expiring(){
         global $session, $pub; 
         $tolerance = (isset($session) ) ? $session->publication->setting_expiring_tolerance : $pub->setting_expiring_tolerance;
         
         return ( $this->subscription_length - $this->get_current_week() <= $tolerance ) ? true : false; 
    }
    
    
    /* --------------------------------------- CRUD --------------------------------------- */

    /**
     * Takes a $_POST containing new or updated subscription data and saves it.
     * If it's new, it will add the initial allowance to the subscription.
     *
     * @return void
     * @param bool 
     * @author epstudios
     */ 
     
    public static function update_subscription() {
        global $session;
        //view($_POST); exit();
        $new_sub = new Subscription( $_POST );
        $new_sub_id = $new_sub->save();
        unset( $_POST['action'] ); // clear, cause we did this.
        
        if ( isset ( $new_sub_id ) ) {
            
            // Future subscriptions need a pause block beforehand.
            
            
            // Add allowance
            $allowances[] = Allowance::instantiate( array(
                'subscription_id' => $new_sub_id,
                'total_duration' => $new_sub->subscription_length,
                'start_date' => $new_sub->start_date,
                'type' => $_POST['type']
            ));
                
            Allowance::_update_allowances( $allowances, $new_sub_id );
            
            header('Location: index.php?page=edit&user='. $new_sub->user_id ); exit;
            
            
        } else {
            $session->add_message('ERROR: There was an error, allowance could not be added for this subscription.');
        }
        
                        
     }      
     
     
          
     /**
     *  Deletes all subscriptions for a user.
     *
     * @return void
     * @param bool 
     * @author epstudios
     */          
     public static function delete_by_user_id($user_id) {
        global $db, $session;
        
        
        $subs = Subscription::find_ids_by_user($user_id);
        
        if ( $subs ) {
            $subs = implode(',', $subs);
            
            //delete the all allowances for this users subscriptions
            $sql =  "DELETE FROM ".Allowance::get_tablename()." WHERE subscription_id IN ($subs)";
            $result = $db->query( $sql );
            
            //delete the all subscription
            $sql =  "DELETE FROM ".self::get_tablename()." WHERE user_id={$user_id}";
            $result = $db->query( $sql );
            
            //Finally delete the user.
            User::delete($user_id);
            
            $session->add_message("SUCCESS: Subscription data for User #{$user_id} has been successfully deleted.");
            return true;
        } else {
            return false;
        }
    } 
     
     /**
     *  Deletes a subscription
     *
     * @return void
     * @param bool 
     * @author epstudios
     */          
     public static function _delete($subscription_id) {
        global $db, $session;
        
            
            //delete the all allowances for this users subscriptions
            $sql =  "DELETE FROM ".Allowance::get_tablename()." WHERE subscription_id = $subscription_id";
            $result = $db->query( $sql );
            
            //delete the all subscription
            $sql =  "DELETE FROM ".self::get_tablename()." WHERE subscription_id = $subscription_id LIMIT 1";
            $result = $db->query( $sql );
            
         
            $session->add_message("SUCCESS: Subscription  #{$subscription_id} has been successfully deleted.");
           
    } 
     
     
    /**
     * VALIDATES the class.
     * 
     * 
     * @access private 
     * @return boolean
     * 
     */
    private function _validate(){
        $validator = new Validator;
        global $session;
        
        // Escape all!
        $validator->escape_class($this);
        
        
        // Get explicit duration
        if (  isset($_POST['total_duration']) ) {
            if ( $_POST['total_duration'] == 0 ) {
                
                if ( $this->is_new() && $_POST['total_duration_other'] <= 0 ) {
                    $this->subscription_length = 1;
                    $session->add_message("ERROR: You cannot set a new subscription with a negative or zero allowance.");
                } else {
                    $this->subscription_length = $_POST['total_duration_other'];
                }
                
            } else {
                $this->subscription_length = $_POST['total_duration'];
            }
        } 
        
        // Get duration based on dates
        if ( isset($_POST['end_date']) && !empty($_POST['end_date']) ) {
            $offset =  get_weeknum( strtotime($_POST['end_date'] ) ) - get_weeknum( strtotime($_POST['start_date'] ) );
            if ($offset > 0 ) {
                $this->subscription_length = $offset + 1;
            } else {
                $this->subscription_length = 1;
                $session->add_message("ERROR: Invalid dates.");
            }
        } 
        

        // No creating subscriptions in the past, from now forward only
        $this->start_week = get_weeknum( strtotime($this->start_date) );
        if ( $this->start_week < get_weeknum() ) {
            $session->add_message("ERROR: Please set a start date which is now, or in the future.");
            return false;
        }

       // Check for current active sub
       if ( $this->has_subscription($this->user_id, $this->publication_id ) ) {
           $session->add_message("ERROR: There is already a subscription running for user id {$this->user_id}. Try adding more time to that one.");
           return false;
       }
       
       if ( $this->start_week > get_weeknum() ) {
                $this->status = 'future';
            } else {
                $this->status = 'active';
            }
       
          
       // Good to go!
       return true;        
    }  
    
    /**
     * Validates and Saves the subscription
     * 
     * 
     * @access private 
     * @return boolean
     * 
     */    
    public function save(){
        global $session;
        if ( $this->_validate() ) {
            $new_id = $this->_update_self();
            if ( $new_id  ){
                $session->add_message("SUCCESS: Subscription #{$new_id} has been successfully saved.");
                return $new_id;
            }
            $session->add_message("ERROR: Subscription #{$new_id} could not be successfully saved.");
            return false;
        } 
    }
    
    
  
     /**
     * UPDATE ATTR updates the publication attributes with new data.
     * 
     * 
     * $ids - an array of ids to udpate.
     * $key - the column to update
     * $value - the new value
     * 
     * @access public 
     * @return publication object
     * 
     */
    public static function update_attr($ids, $key, $value){
        global $db;
        
        if (!is_array($ids)) return false;
        
        $ids = implode(",", $ids);
    
        $sql =  "UPDATE ". self::get_tablename() . " ";
        $sql .= "SET {$key}='{$value}' ";
        $sql .= "WHERE subscription_id IN ({$ids})";
        $result = $db->query( $sql );
        return ($result) ? TRUE : FALSE;
        
    }
    /**
     * UPDATE ATTS updates the subscription attributes with new data based on a key => value array
     * 
     * 
     * $ids - an array of ids to udpate.
     * $key - the column to update
     * $value - the new value
     * 
     * @access public 
     * @return publication object
     * 
     */
    public static function update_atts( $array ){
        global $db;
        
        // I think this is broken. the MYSQL Syntax appears to be off. 
        // this function doesn't appear to be called from anywhere.
        
        /*
        if (!is_array($array)) return false;
        $id_set = implode(',', array_keys($array));
        $sql = "UPDATE ".self::get_tablename()."
                SET start_date = CASE subscription_id ";
                foreach( $array as $id => $value ) {
                    $sql .= sprintf("WHEN %d THEN '%s' ", $id, $value);
                }
                $sql .= "END WHERE subscription_id IN ($id_set)";
               
                
        $result = $db->query( $sql );
        return ( $db->affected_rows() );
        */
        return;
    }
    
    
    /**
     * UPDATE SELF a function which will create a new subscription. We use update_attr to made updates.
     * 
     * 
     * @access public 
     * @return publication object
     * 
     */
    private function _update_self() {
        global $db;
        global $session;
        
        if( $this->is_new() ) {
            $sql =  "INSERT INTO ".self::get_tablename()." ";
            $sql .= "(subscription_datestamp, user_id, publication_id, start_week, status) ";
            $sql .= "VALUES ('".date( 'Y-m-d H:i:s', time() )."', '{$this->user_id}', '{$this->publication_id}', '{$this->start_week}', '{$this->status}')";
        
            $result = $db->query( $sql );
            
            if  ($result ) {
                $sql =  "SELECT LAST_INSERT_ID() AS subscription_id FROM ".self::get_tablename();
                $result_set = $db->query( $sql );
                $row = $db->fetch_array($result_set);
                return $row['subscription_id'];
            }
        }
        return false;
    }



    /**
     * instantiate creates a new object from an array.
     * 
     * 
     * @access public 
     * @return publication object
     * 
     */
    public static function instantiate( $record ){
        $object = new self;
        
        foreach ( $record as $key=>$value ) {
            if ( $object->_has_attribute($key))  $object->$key = $value;
        }
        $object->start_date = date("F j Y", get_date_from_weeknum( $object->start_week ));
        
        return $object; 
    }
     /**
     * instantiate initializes an existing object from an array.
     * 
     * 
     * @access public 
     * @return publication object
     * 
     */
    private function _instantiate( $record ){
        foreach ( $record as $key => $value ) {
            if ( $this->_has_attribute($key))  $this->$key =  $value;
        }
        if ( !$this->is_new() ) $this->start_date = date("F j Y", get_date_from_weeknum( $this->start_week ));
        
    }
    /**
     * instantiate creates an array of new objects from a database query
     * 
     * 
     * @access public 
     * @return publication object
     * 
     */
    public static function instantiate_from_rows( $result_set ){
        global $db;
        if ( $db->affected_rows() == 0 ) return false;
        $object_array = array();
        while ($row = $db->fetch_array($result_set)) {
            $object_array[] = new Subscription($row);
        }
        return $object_array;
    }
    
    
    
    /* --------------------------------------- QUERIES --------------------------------------- */
    
     
    /**
     * FIND BY RECENTLY EXPIRED a function which will return only subscriptions which have expired within the tolerance set
     * 
     * WARNING can be hefty!!
     * 
     * $publication_id - the id to fetch
     * $offset - for pagination, the number of rows to offset the query
     * $filter - if we are filtering, the filter is generally created and sent ready to insert.
     * 
     * @access public 
     * @return object
     * 
     */
 
    public static function find_by_recently_expired( $publication_id, $tolerance = null ) {
        global $session;
        if( !isset($tolerance) ) $tolerance = $session->publication->setting_expired_tolerance;
        if( !isset($publication_id) ) return false;
        global $db;
         
         
         $user              = User::get_tablename();
         $allowance         = Allowance::get_tablename();
         $sub               = self::get_tablename();
         $pub               = Publication::get_tablename();
         
         $this_week         = get_weeknum();
         $week_tolerance    = $this_week - $tolerance;
         
         $result_set = $db->query( "
         SELECT *, 
         GROUP_CONCAT($allowance.allowance_id ) AS allowance_ids, 
         GROUP_CONCAT($allowance.total_duration ) AS total_durations, 
         GROUP_CONCAT($allowance.datestamp ) AS datestamps, 
         GROUP_CONCAT($allowance.queue ) AS queues, 
         GROUP_CONCAT($allowance.total_duration ) AS total_durations, 
         GROUP_CONCAT($allowance.type ) AS types,
         SUM( $allowance.total_duration ) as sum_duration, 
         $sub.subscription_id as subscription_id   
         FROM $sub 
         LEFT JOIN $user ON $user.user_id = $sub.user_id 
         LEFT JOIN $pub ON $pub.publication_id = $sub.publication_id 
         LEFT JOIN $allowance ON $allowance.subscription_id = $sub.subscription_id 
         WHERE $sub.publication_id = {$publication_id} 
         AND status = 'inactive' 
         AND $sub.user_id NOT IN ( SELECT user_id FROM $sub WHERE status != 'inactive' ) 
         GROUP BY $sub.subscription_id 
         HAVING COALESCE( SUM($allowance.total_duration), 0 ) + $sub.start_week BETWEEN $week_tolerance AND $this_week
         ");
         
         // HAVING is the key here.
         // We COALESCE the total duration for the allowances (default 0) and add it to the starting week to get when this
         // Sub expired. if it is within the tolerace we select and return it.
         // ALSO noteworthy is the NOT IN clause, we do not want to select an inactive instance if the user
         // Has a currently active sub - so as not to duplicate labels.
         
         
        $object_array = array();

        while ($row = $db->fetch_array($result_set)) {
            $object_array[] = new Subscription($row);
        }
        
        return $object_array;

    }
    
    /**
     * FIND BY RECENTLY EXPIRED a function which will return all subscriptions, including those which have recently expired.
     * 
     * WARNING can be hefty!!
     * 
     * $publication_id - the id to fetch
     * $offset - for pagination, the number of rows to offset the query
     * $filter - if we are filtering, the filter is generally created and sent ready to insert.
     * 
     * @access public 
     * @return objects
     * 
     */
 
    public static function find_all_within_tolerance_by_publication ( $publication_id, $tolerance = null, $filter='', $sort='' ) {
        if( !isset($tolerance) ) $tolerance = $session->pub->setting_expired_tolerance;
        if( !isset($publication_id) ) return false;
        
        global $db;
         
         
         $user              = User::get_tablename();
         $allowance         = Allowance::get_tablename();
         $sub               = self::get_tablename();
         $pub               = Publication::get_tablename();
         
         $this_week         = get_weeknum();
         $week_tolerance    = $this_week - $tolerance;
         
         $result_set = $db->query( "
         SELECT *, 
         GROUP_CONCAT($allowance.allowance_id ) AS allowance_ids, 
         GROUP_CONCAT($allowance.total_duration ) AS total_durations, 
         GROUP_CONCAT($allowance.datestamp ) AS datestamps, 
         GROUP_CONCAT($allowance.queue ) AS queues, 
         GROUP_CONCAT($allowance.total_duration ) AS total_durations, 
         GROUP_CONCAT($allowance.type ) AS types,
         SUM( $allowance.total_duration ) as sum_duration, 
         $sub.subscription_id as subscription_id   
         FROM $sub 
         LEFT JOIN $user ON $user.user_id = $sub.user_id 
         LEFT JOIN $pub ON $pub.publication_id = $sub.publication_id 
         LEFT JOIN $allowance ON $allowance.subscription_id = $sub.subscription_id 
         WHERE $sub.publication_id = {$publication_id} 
         AND $sub.trashed = 0 {$filter} 
         GROUP BY $sub.user_id 
         HAVING COALESCE( SUM($allowance.total_duration), 0 ) + $sub.start_week > $week_tolerance
         {$sort}
         ");

         
         // HAVING is the key here.
         // We COALESCE the total duration for the allowances (default 0) and add it to the starting week to get when this
         // Sub expired. if it is within the tolerace we select and return it.
         // ALSO noteworthy is the NOT IN clause, we do not want to select an inactive instance if the user
         // Has a currently active sub - so as not to duplicate labels.
         
         
        $object_array = array();

        while ($row = $db->fetch_array($result_set)) {
            $object_array[] = new Subscription($row);
        }
        return $object_array;

    }
    
    
    /**
     * FIND BY PUBLICATION a function which will return all subscriptions for a given publication id based on parameters
     * 
     * WARNING can be hefty!!
     * 
     * $publication_id - the id to fetch
     * $offset - for pagination, the number of rows to offset the query
     * $filter - if we are filtering, the filter is generally created and sent ready to insert.
     * 
     * @access public 
     * @return object
     * 
     */
 
    public static function find_by_publication($publication_id, $offset = 0, $filter='', $sort='', $count = null) {
        global $db, $RECORDS_PER_PAGE;
         $count = ( isset($count) )  ? $count : $RECORDS_PER_PAGE;
         $user = User::get_tablename();
         $allowance = Allowance::get_tablename();
         $sub = self::get_tablename();
         $pub = Publication::get_tablename();
         
         $result_set = $db->query("
         SELECT *, 
         GROUP_CONCAT($allowance.allowance_id ) AS allowance_ids, 
         GROUP_CONCAT($allowance.total_duration ) AS total_durations, 
         GROUP_CONCAT($allowance.datestamp ) AS datestamps, 
         GROUP_CONCAT($allowance.queue ) AS queues, 
         GROUP_CONCAT($allowance.total_duration ) AS total_durations, 
         GROUP_CONCAT($allowance.type ) AS types,
         $sub.subscription_id as subscription_id   
         FROM $sub 
         LEFT JOIN $user ON $user.user_id = $sub.user_id 
         LEFT JOIN $pub ON $pub.publication_id = $sub.publication_id 
         INNER JOIN $allowance ON $allowance.subscription_id = $sub.subscription_id 
         WHERE $sub.publication_id={$publication_id} 
         AND $sub.trashed = 0 {$filter} 
         GROUP BY $sub.subscription_id 
         {$sort} 
         LIMIT $count OFFSET {$offset} 
         ");
         
        // RETURNS the ARRAY OF OBJECTS.
        // return self::instantiate_from_rows( $result_set );
        
        $object_array = array();

        while ($row = $db->fetch_array($result_set)) {
            $object_array[] = new Subscription($row);
        }
        return $object_array;
    }
    
   
     /**
     * GETS ONLY THE CURRENTLY ACTIVE SUB BY AN ID
     * 
     * $user_id - the id to fetch
     * 
     * @access public 
     * @return object
     * 
     */
    public static function find_by_user_id( $user_id ) {
        global $db;
        $user = User::get_tablename();
         $allowance = Allowance::get_tablename();
         $sub = self::get_tablename();
         $pub = Publication::get_tablename();
        
        $result_set = $db->query( "
         SELECT *, 
         GROUP_CONCAT($allowance.allowance_id ) AS allowance_ids, 
         GROUP_CONCAT($allowance.total_duration ) AS total_durations, 
         GROUP_CONCAT($allowance.datestamp ) AS datestamps, 
         GROUP_CONCAT($allowance.queue ) AS queues, 
         GROUP_CONCAT($allowance.total_duration ) AS total_durations, 
         GROUP_CONCAT($allowance.type ) AS types  
         FROM $sub 
         LEFT JOIN $user ON $user.user_id = $sub.user_id 
         LEFT JOIN $pub ON $pub.publication_id = $sub.publication_id 
         LEFT JOIN $allowance ON $allowance.subscription_id = $sub.subscription_id 
         WHERE $sub.user_id={$user_id} 
         AND $sub.trashed = 0 
         GROUP BY $sub.subscription_id 
         ORDER BY $sub.subscription_id 
         ");
        
              
        $object_array =  self::instantiate_from_rows( $result_set );
        return $object_array;
    }
    
    
    
    /**
     * FIND BY ID find a sub by its id
     * 
     * WARNING, HEFTY!
     * 
     * $user_id - the id to fetch
     * 
     * @access public 
     * @return object
     * 
     */
    public static function find_by_id($subscription_id) {
        global $db;
        $user       = User::get_tablename();
        $allowance  = Allowance::get_tablename();
        $sub        = self::get_tablename();
        $pub        = Publication::get_tablename();
        
        $result_set = $db->query( "
         SELECT *, 
         GROUP_CONCAT($allowance.allowance_id ) AS allowance_ids, 
         GROUP_CONCAT($allowance.total_duration ) AS total_durations, 
         GROUP_CONCAT($allowance.datestamp ) AS datestamps, 
         GROUP_CONCAT($allowance.queue ) AS queues, 
         GROUP_CONCAT($allowance.total_duration ) AS total_durations, 
         GROUP_CONCAT($allowance.type ) AS types,
         $sub.subscription_id as subscription_id 
         FROM $sub 
         LEFT JOIN $user ON $user.user_id = $sub.user_id 
         LEFT JOIN $pub ON $pub.publication_id = $sub.publication_id 
         LEFT JOIN $allowance ON $allowance.subscription_id = $sub.subscription_id 
         WHERE $sub.subscription_id=$subscription_id 
         AND $sub.trashed = 0 AND status != 'inactive' 
         GROUP BY $sub.subscription_id LIMIT 1
         ");
        $object_array =  self::instantiate_from_rows( $result_set );
        return $object_array[0];
    }
    
    
    
    
    /**
     * FIND IDS USER ID find subscription ids by their user id
     * 
     * $user_id - the id to fetch
     * 
     * @access public 
     * @return object
     * 
     */
    public static function find_ids_by_user($user_id) {
        global $db;
        $result_set = $db->query( "
         SELECT subscription_id FROM " . self::get_tablename() . " 
         WHERE user_id={$user_id} 
         AND trashed = 0" );
        
        $array = array();
        while ($row = $db->fetch_array($result_set)) {
            $array[] = $row['subscription_id'];
        }
        return $array;

    }
    
    
    
    
    
    /* --------------------------------------- SEARCHES --------------------------------------- */
    
    
    
     /**
     * ADVANCED SEARCH
     * 
     * WARNING, HEFTY!
     * TODO:: REWRITE!!
     * @access public 
     * @return object
     * 
     */
    public static function advanced_search($search) {
        global $db;
        $search = $db->prepare_search_params( $search );
        $sub    = self::get_tablename();
        $user   = User::get_tablename();
        $allowance = Allowance::get_tablename();
        $pub = Publication::get_tablename();
        
        $result_set = $db->query( "
         SELECT *, 
         GROUP_CONCAT($allowance.allowance_id ) AS allowance_ids, 
         GROUP_CONCAT($allowance.total_duration ) AS total_durations, 
         GROUP_CONCAT($allowance.datestamp ) AS datestamps, 
         GROUP_CONCAT($allowance.queue ) AS queues, 
         GROUP_CONCAT($allowance.total_duration ) AS total_durations, 
         GROUP_CONCAT($allowance.type ) AS types,
         $sub.subscription_id as subscription_id 
         FROM $sub 
         LEFT JOIN $user ON $user.user_id = $sub.user_id 
         LEFT JOIN $pub ON $pub.publication_id = $sub.publication_id 
         LEFT JOIN $allowance ON $allowance.subscription_id = $sub.subscription_id 
         WHERE $sub.trashed = 0 $search 
         GROUP BY $sub.subscription_id 
         ORDER BY $user.displayname
         ");
         
        return self::instantiate_from_rows( $result_set );

    }
    



    /* --------------------------------------- DATABASE --------------------------------------- */

        
    public static function find_by_sql( $sql="") {
        global $db;
        $result_set = $db->query( $sql );
        
        $object_array = array();
        while ($row = $db->fetch_array($result_set)) {
            $object_array[] = new Subscription($row);
        }
        // RETURNS AN ARRAY OF OBJECTS.
        return $object_array;
    }

    
    
    private function _has_attribute ( $key ) {
        //  NOTE: INCLUDES PRIVATE ATTRIBUTES.
        $object_vars = get_object_vars($this);
        return array_key_exists($key, $object_vars);
        
    }
    
    /* --------------------------------------- MAINTENANCE --------------------------------------- */
   
    /**
     * load an fresh instance of a sub and re-write the status. Used when adjusting allowances.
     *
     * @return void
     * @param bool 
     * @author epstudios
     */ 
     public static function refresh_status($subscription_id) {
       global $session;


       $object = self::find_by_id($subscription_id); 
       $new_status = 'active';
       
       if($object) {
    
            if( isset($object->subscription_length) &&  isset($object->subscription[$object->get_current_week()]) ){
               
               if($object->subscription[$object->get_current_week()] == 1 ){
                   if ( $object->is_expiring() ) {
                        $new_status = 'expiring';
                   } else {
                       $new_status = 'active';
                   }
               } elseif ($object->subscription[$object->get_current_week()] == 2) {
                   $new_status = 'paused';
               } else {
                   $new_status = 'inactive';
               }
               
            } else {
               if( $object->get_current_week() < 0) {
                   $new_status = 'future';
               } else {
                   $new_status = 'inactive';
               }
            }
            
            view($new_status);
            self::update_attr(array($subscription_id), 'status', $new_status );
            return true;  
       }
       return false;    
    }
    
        
    /**
     * SCRUB method iterates through all non-trashes, non-expired subscriptions and verifies their status.
     * This method should be called every time an update is made, every morning, and every week on rollover.
     * 
     * @access public 
     * @return bool
     * 
     */
    public static function scrub_subs($publication_id){
       global $session, $db;
       
       $current_publication = Publication::find_by_id($publication_id);
       $ids = array(
           'inactive' => array(),
           'active' => array(),
           'paused' => array(),
           'expiring' => array()
       );
       $new_starts = array();
       $total = '';
       
      $result_set = $db->query( "SELECT COUNT(subscription_id) as total FROM ".self::get_tablename());
      $total = $db->fetch_array($result_set);
      $total = array_shift( $total );

      for( $i = 0; $i < $total; $i += BULK_RECORD_STEP ) {
           
           $objects = self::find_by_publication($publication_id,  $i, '', '', BULK_RECORD_STEP);
           if ($objects) {
               foreach ($objects as $object ){
                   // Get the flag for each current week according to the subscription array
                   // 1 is active
                   // 2 is paused
                   // any other value and we default to inactive.
                   
                   if( isset( $object->subscription_length ) && $object->subscription_length > 0 && isset($object->subscription[$object->get_current_week()]) ){
                       if( $object->subscription[$object->get_current_week()] == 1 ){
                           if ( $object->is_expiring() ) {
                                $ids['expiring'][] = $object->subscription_id;
                           } else {
                                $ids['active'][] = $object->subscription_id;
                           }
                            
                       } elseif ($object->subscription[$object->get_current_week()] == 2) {
                           $ids['paused'][] = $object->subscription_id;
                       } else {
                           $ids['inactive'][] = $object->subscription_id;
                       }
                       
                   } else {
                       $ids['inactive'][] = $object->subscription_id;
                   }
    
                   
               }           
           }

           $objects = null; unset($objects);
       }

       view($ids);

        if ( isset($ids) && !empty($ids) ) {
        foreach ( $ids as $status => $id_set ) {
               $id_set = array_filter($id_set);
               view($id_set);
               view($status);
               if($id_set) self::update_attr($id_set, 'status', $status );
           }
        }

    }


}
?>